<script setup lang="tsx">
import { computed, inject, reactive, ref, watch } from "vue";
import { ClDialog, ClGrid, Grid, GridUtils, useDialog } from "@chulei-ui/components";
import { useDebounceFn, useLocalStorage } from "@vueuse/core";
import { BigDecimal } from "@chulei-ui/utils";
import { Container } from "typedi";
import { storeToRefs } from "pinia";
import { NumberUtils } from "../../utils";
import { ContractService } from "../../repositories/ContractService";
import { useMarketStore } from "../../cache/MarketStore";
import { useCacheStore } from "../../sde/cache";
import type { TypeMaterialsItem } from "../../sde/entity";
import type { Contract } from "../../repositories/contracts/entity";
import type { GridInstance, PageFetchParams } from "@chulei-ui/components";
import { ContractGridInstance } from "~pages/contracts/tokens";
import UniverseTypeIcon from "~components/universe-type/UniverseTypeIcon.vue";
import { useContract } from "~pages/contracts/use-contract";

const props = defineProps<{ contract: Contract }>();

const discount = useLocalStorage("contract-jita-discount", 85);

const contractService = Container.get(ContractService);

const marketStore = useMarketStore();
const cacheStore = useCacheStore();

const { typePrices } = storeToRefs(marketStore);

const refiningEfficiency = useLocalStorage("contract-refiningEfficiency", 100);
const selections = ref<PriceItem[]>([]);
const gridRef = ref<GridInstance>();

const { dialogRef, show, hide } = useDialog<number>(true, {
  async init() {
    if (props.contract.settlement_discount !== null) {
      discount.value = props.contract.settlement_discount;
    }
  },
});

watch(
  refiningEfficiency,
  useDebounceFn(() => {
    gridRef.value!.refresh();
    //同步更新选中项的组成部分
    selections.value = selections.value.map((item) => {
      item.materials = getTypeMaterials(item.id, item.quantity, refiningEfficiency.value);
      return item;
    });
  }, 100)
);

const formatTooltip = (value: number) => {
  return `吉他收单最高${value}%`;
};

const marks = reactive({
  85: {
    style: {
      color: "#1989FA",
    },
    label: "85%",
  },
  10: {
    style: {
      color: "green",
    },
    label: "10%",
  },
  200: {
    style: {
      color: "red",
    },
    label: "200%",
  },
});

const discountAmount = computed(() => {
  return BigDecimal.form(extractSummaryBuyPrice.value)!
    .plus(unExtractSummaryBuyPrice.value)
    .multiply(discount.value! / 100)
    .toFixed(2)!
    .toNumber()!;
});

const { calcTotalPrice } = useContract();

const contractGridRef = inject(ContractGridInstance)!;
const doSettlement = async () => {
  const settlementInfo = {
    contract_id: props.contract.contract_id,
    settlement_jita_price: calcTotalPrice(props.contract, (price) => price.buy_high),
    settlement_estimate_price: calcTotalPrice(props.contract, (price) => price.estimate_price),
    settlement_discount: discount.value,
    settlement_price: discountAmount.value,
  };
  await contractService.save({ ...settlementInfo } as Contract);
  contractGridRef.value!.updateRows<Contract>(
    [{ ...props.contract, ...settlementInfo } as Contract],
    (contract) => contract.contract_id
  );
};

const columns = ref<Grid.Column[]>([
  {
    field: "name",
    headerName: "物品",
    checkboxSelection: true,
    headerCheckboxSelection: true,
  },
  {
    field: "quantity",
    headerName: "数量",
    valueGetter: GridUtils.ValueGetter<TypeMaterialsItem>(({ data }) => {
      return data!.quantity;
    }),
    ...Grid.cellRender<PriceItem>(({ value }) => {
      return NumberUtils.readableText(value);
    }),
  },
  {
    field: "price.buy_high_total",
    headerName: "吉他收单总价",
    valueGetter: GridUtils.ValueGetter<PriceItem>(({ data }) => {
      return typePrices.value.get(data!.id)?.buy_high;
    }),
    ...Grid.cellRender<PriceItem>(
      ({ data, value }) => {
        if (!value) return "";
        return `${NumberUtils.readableText(BigDecimal.form(value)!.multiply(data!.quantity)!.toFixed(2)!.toNumber())}`;
      },
      ({ data }: { data: any }) => {
        return NumberUtils.readableText(data.totalBuyPrice);
      }
    ),
  },
  {
    field: "price.buy_high",
    headerName: "吉他收单单价",
    valueGetter: GridUtils.ValueGetter<PriceItem>(({ data }) => {
      return typePrices.value.get(data!.id)?.buy_high;
    }),
    ...Grid.cellRender<PriceItem>(({ value }) => {
      return NumberUtils.readableText(value);
    }),
  },
  {
    field: "price.estimate_price_total",
    headerName: "预估总价",
    valueGetter: GridUtils.ValueGetter<PriceItem>(({ data }) => {
      return typePrices.value.get(data!.id)?.estimate_price;
    }),
    ...Grid.cellRender<PriceItem>(
      ({ data, value }) => {
        if (!value) return "";
        return `${NumberUtils.readableText(BigDecimal.form(value)!.multiply(data!.quantity)!.toFixed(2)!.toNumber())}`;
      },
      ({ data }: { data: any }) => {
        return NumberUtils.readableText(data.totalEstimatePrice);
      }
    ),
  },
  {
    field: "price.estimate_price",
    valueGetter: GridUtils.ValueGetter<PriceItem>(({ data }) => {
      return typePrices.value.get(data!.id)?.estimate_price;
    }),
    headerName: "预估单价",
    ...Grid.cellRender<PriceItem>(({ value }) => {
      return NumberUtils.readableText(value);
    }),
  },
  {
    field: "extract",
    headerName: "精炼产物",
    ...Grid.alwaysCellRender<PriceItem>(({ data }) => {
      if (!data?.materials) return;
      return (
        <el-scrollbar>
          <div class="space-x-2 flex items-center">
            {data.materials.map((item) => (
              <el-tag class="flex-shrink-0" disable-transitions type="info">
                <span class="flex items-center">
                  <UniverseTypeIcon id={item.id} />
                  <span>
                    {item.name}({NumberUtils.readableText(item.quantity)})
                  </span>
                </span>
              </el-tag>
            ))}
          </div>
        </el-scrollbar>
      );
    }),
  },
]);

type PriceItem = {
  id: number;
  name: string;
  quantity: number;
  /**
   * 提炼产物
   */
  materials?: TypeMaterialsItem[];
};

const groupItems = computed(() => {
  return Array.from(
    (props.contract.items ?? [])
      .reduce((map, item) => {
        const count = map.get(item.type_id!) ?? 0;
        map.set(item.type_id!, count + item.quantity!);
        return map;
      }, new Map<number, number>())
      .entries()
  )
    .map(([id, quantity]) => {
      const type = cacheStore.getType(id)!;
      if (!type) return null;
      const price = typePrices.value.get(type.id);
      return {
        id: type.id,
        name: type.name,
        quantity,
        price,
      };
    })
    .filter((i) => i);
});

const totalExtractItems = computed(() => {
  return Array.from(
    selections.value
      .flatMap((item) =>
        (item.materials ?? []).map((material) => {
          return {
            ...material,
          };
        })
      )!
      .reduce((map, item: TypeMaterialsItem) => {
        let total = map.get(item.id);
        if (!total) {
          map.set(item.id, { ...item, quantity: 0 });
          total = map.get(item.id);
        }
        total!.quantity += item.quantity;
        return map;
      }, new Map<number, TypeMaterialsItem>())
      .values()
  );
});

const getTypeMaterials = (typeId: number, quantity: number, efficiency: number) => {
  const type = cacheStore.getType(typeId)!;
  const materials = type!.materials;
  const batch = quantity / type.portionSize;
  return materials?.map((material) => {
    return {
      id: material.type.id,
      name: material.type.name,
      quantity: Math.floor((batch * material.quantity * efficiency) / 100),
    } as TypeMaterialsItem;
  });
};

const typeMaterials = computed(() => {
  return groupItems.value.map((item) => {
    return {
      ...item,
      materials: getTypeMaterials(item!.id, item!.quantity, refiningEfficiency.value ?? 100),
    } as PriceItem;
  });
});

const typeSummary = computed(() => {
  return calcSummary(typeMaterials.value);
});

const rowData = async ({ pageNum }: PageFetchParams) => {
  if (pageNum > 1) return [];
  gridRef.value!.setFooterData([typeSummary.value]);
  return typeMaterials.value;
};

const calcSummary = (items: PriceItem[]) => {
  return {
    totalBuyPrice: items
      .map((item) => {
        return BigDecimal.form(typePrices.value.get(item.id)?.buy_high ?? 0)?.multiply(item.quantity)!;
      })
      .reduce((total, ele) => total!.plus(ele)!, BigDecimal.form(0)!)!
      .toFixed(2)!
      .toNumber(),
    totalEstimatePrice: items
      .map((item) => {
        return BigDecimal.form(typePrices.value.get(item.id)?.estimate_price ?? 0)!.multiply(item.quantity)!;
      })
      .reduce((total, ele) => total!.plus(ele)!, BigDecimal.form(0)!)!
      .toFixed(2)!
      .toNumber(),
  };
};

const extractSummaryBuyPrice = computed(() => {
  return totalExtractItems.value
    .map((item) => {
      const price = typePrices.value.get(item.id);
      if (!price) return null;
      return BigDecimal.form(price.buy_high ?? 0)!.multiply(item.quantity)!;
    })
    .filter((i) => i)
    .reduce((total, ele) => total!.plus(ele!)!, BigDecimal.form(0)!)!
    .toFixed(2)!
    .toNumber();
});

const unExtractSummaryBuyPrice = computed(() => {
  return groupItems.value
    .filter((item) => !selections.value.some((selected) => selected.id === item!.id) || selections.value.length === 0)
    .map((item) => {
      const price = typePrices.value.get(item!.id);
      if (!price) return null;
      return BigDecimal.form(price.buy_high ?? 0)!.multiply(item!.quantity)!;
    })
    .filter((i) => i)
    .reduce((total, ele) => total!.plus(ele!)!, BigDecimal.form(0)!)!
    .toFixed(2)!
    .toNumber();
});

const gridOptions = ref<Grid.Options>({
  onSelectionChanged(event) {
    selections.value = event.api.getSelectedRows();
  },
});

defineExpose({
  show,
});
/**
 * 合同结算弹框
 */
defineOptions({
  name: "ContractSettlementDialog",
});
</script>

<template>
  <cl-dialog ref="dialogRef" fullscreen :on-confirm="doSettlement" @close="hide">
    <template #header>合同明细 </template>
    <div class="h-full">
      <div class="flex flex-col justify-center items-center">
        <el-slider
          v-model="discount"
          size="small"
          class="mb-5"
          style="width: 90%"
          show-tooltip
          :format-tooltip="formatTooltip"
          placeholder="请输入吉他折扣价格"
          :format-value-text="formatTooltip"
          :marks="marks"
          :max="200"
          :min="10"
        />
        <div>
          <span>折后价格：</span>
          <span style="color: var(--el-color-danger)">
            {{ NumberUtils.readableText(discountAmount) }}
          </span>
        </div>
      </div>
      <div style="height: calc(100% - 200px)">
        <cl-grid ref="gridRef" :grid-options="gridOptions" :columns="columns" :row-data="rowData">
          <template #toolbar>
            <div class="flex items-center">
              <el-input-number
                v-model="refiningEfficiency"
                :controls="false"
                :min="50"
                :max="100"
                placeholder="请输入精炼效率"
              />
              <el-tag style="margin-left: -3px" size="large" type="info">精炼效率(%)</el-tag>
            </div>
          </template>
        </cl-grid>
        <el-divider>
          提取物价值({{ NumberUtils.readableText(extractSummaryBuyPrice) }}) - 未提取物价值({{
            NumberUtils.readableText(unExtractSummaryBuyPrice)
          }})
        </el-divider>
        <el-space wrap>
          <el-tag v-for="item in totalExtractItems" :key="item.id" type="success" disable-transitions>
            <div class="flex items-center">
              <UniverseTypeIcon :id="item.id" />
              {{ item.name }} {{ NumberUtils.readableText(item.quantity) }}
            </div>
          </el-tag>
        </el-space>
      </div>
    </div>
  </cl-dialog>
</template>

<style lang="scss">
.el-dialog {
  &.is-fullscreen {
    display: flex;
    flex-direction: column;
    .el-dialog__body {
      height: 100%;
      .el-scrollbar__view {
        height: 100%;
        .custom-cell {
          .el-scrollbar {
            display: flex;
            .el-scrollbar__wrap {
              display: flex;
            }
          }
          .el-scrollbar__view {
            height: unset;
            display: flex;
          }
        }
      }
    }
  }
}
</style>
